package netTracker;

import java.util.*;

/**
 * A utility class for mapping frequencies to the names of notes.
 * 
 * @author David
 */

@SuppressWarnings("serial")

public class NoteMapper {
	
	public static final Double FREQ_NOT_FOUND = -10.0;
	
	/**
	 * Create a map of Note Name, Frequency pairs.
	 */
	private static final HashMap<String, Double> NAME_TO_FREQ =
					new HashMap<String, Double>(){
						{
							put("", Note.EMPTY);
							put("---", Note.CUTOFF);
							put("C-0", 016.35);
							put("C#0", 017.32); 
							put("D-0", 018.35);
							put("D#0", 019.45);
							put("E-0", 020.60);
							put("F-0", 021.83);
							put("F#0", 023.12);
							put("G-0", 024.50);
							put("G#0", 025.96);
							put("A-0", 027.50);
							put("A#0", 029.14);
							put("B-0", 030.87);
							put("C-1", 032.70);
							put("C#1", 034.65); 
							put("D-1", 036.71);
							put("D#1", 038.89);
							put("E-1", 041.20);
							put("F-1", 043.65);
							put("F#1", 046.25);
							put("G-1", 049.00);
							put("G#1", 051.91);
							put("A-1", 055.00);
							put("A#1", 058.27);
							put("B-1", 061.74);
							put("C-2", 065.41);
							put("C#2", 069.30); 
							put("D-2", 073.42);
							put("D#2", 077.78);
							put("E-2", 082.41);
							put("F-2", 087.31);
							put("F#2", 092.50);
							put("G-2", 098.00);
							put("G#2", 103.83);
							put("A-2", 110.00);
							put("A#2", 116.54);
							put("B-2", 123.47);
							put("C-3", 130.81);
							put("C#3", 138.59); 
							put("D-3", 146.83);
							put("D#3", 155.56);
							put("E-3", 164.81);
							put("F-3", 174.61);
							put("F#3", 185.00);
							put("G-3", 196.00);
							put("G#3", 207.65);
							put("A-3", 220.00);
							put("A#3", 233.08);
							put("B-3", 246.94);							
							put("C-4", 261.63);
							put("C#4", 277.18); 
							put("D-4", 293.66);
							put("D#4", 311.13);
							put("E-4", 329.63);
							put("F-4", 349.23);
							put("F#4", 369.99);
							put("G-4", 392.00);
							put("G#4", 415.30);
							put("A-4", 440.00);
							put("A#4", 466.46);
							put("B-4", 493.88);
							put("C-5", 523.25);
							put("C#5", 554.37); 
							put("D-5", 587.33);
							put("D#5", 622.25);
							put("E-5", 659.26);
							put("F-5", 698.46);
							put("F#5", 739.99);
							put("G-5", 783.99);
							put("G#5", 830.61);
							put("A-5", 880.00);
							put("A#5", 932.33);
							put("B-5", 987.77);
							put("C-6", 261.63); // TODO put in values from here on
							put("C#6", 277.18); 
							put("D-6", 293.66);
							put("D#6", 311.13);
							put("E-6", 329.63);
							put("F-6", 349.23);
							put("F#6", 369.99);
							put("G-6", 392.00);
							put("G#6", 415.30);
							put("A-6", 440.00);
							put("A#6", 466.46);
							put("B-6", 493.88);
							put("C-7", 261.63);
							put("C#7", 277.18); 
							put("D-7", 293.66);
							put("D#7", 311.13);
							put("E-7", 329.63);
							put("F-7", 349.23);
							put("F#7", 369.99);
							put("G-7", 392.00);
							put("G#7", 415.30);
							put("A-7", 440.00);
							put("A#7", 466.46);
							put("B-7", 493.88);	
							put("C-8", 261.63);
							put("C#8", 277.18); 
							put("D-8", 293.66);
							put("D#8", 311.13);						
						}
					};
			
	/**
	 * Use the above map to create a backwards map.
	 */
	private static final HashMap<Double, String> FREQ_TO_NAME = 
					new HashMap<Double, String>(){
						{
							Set<String> names = NAME_TO_FREQ.keySet();
							Iterator<String> itr = names.iterator();
							while(itr.hasNext()){
								String name = itr.next();
								put(NAME_TO_FREQ.get(name), name);
							}
						}
					};
	
	/**
	 * Maps a frequency to a string representation of the closest note.
	 * @param frequency the frequency to look up
	 * @return the string representation of the frequency
	 */
	public static String lookup(double frequency){
		return FREQ_TO_NAME.get(frequency);
	}

	/**
	 * Maps a string to the note matching the string.
	 * @param noteName the string representation of the note
	 * @return the note corresponding to the given string or FREQ_NOT_FOUND if no mapping exists.
	 */
	public static Double lookup(String noteName) {
		if (NAME_TO_FREQ.containsKey(noteName))	
			return NAME_TO_FREQ.get(noteName);
		else
			return FREQ_NOT_FOUND;
	}
	
	/**
	 * Converts a given frequency to the nearest midi pitch number.
	 * This algorithm was modified from the original source by Adam Kirby, 
	 * from jm.util in the JMusic collection.
	 * @param frequency the frequency to convert
	 * @return the midi pitch number
	 */
    public static final int getMidiPitchByFrequency(double frequency) {
    	return Math.round((float)(12 *(Math.log(frequency / 6.875) / Math.log(2)) - 3));
    }

}
